<?php
// +----------------------------------------------------------------------
// | 动作服务层
// +----------------------------------------------------------------------
// | 主要服务于钉钉数据对接
// +----------------------------------------------------------------------
// | 错误编码头 236xxx
// +----------------------------------------------------------------------
namespace common\service;

use Common\Model\UserModel;
use EasyDingTalk\Application;

class DingTalkService
{
    // 钉钉配置
    protected $config = [];

    /**
     * EasyDingTalk对象
     * @var \EasyDingTalk\Application
     */
    protected $dingTalkApp = null;

    /**
     * 缓存Key
     * @var string
     */
    protected $cacheKey = 'dingTalk_user_list';

    /**
     * 初始化对象
     * @param int $userId
     */
    public function init($userId = 0)
    {
        if (empty($this->config)) {
            $this->getConfig($userId);
        }

        if (!empty($this->config)) {
            $this->dingTalkApp = new Application($this->config);
        }
    }

    /**
     * 设置钉钉配置
     * @param $config
     */
    public function setConfig($config)
    {
        $this->config = $config;
        $this->cacheKey = 'dingTalk_user_list_' . $config['corp_id'];
    }

    /**
     * 获取当前用户所在部门绑定的钉钉配置
     * @param $userId
     */
    public function getConfig($userId)
    {
        // 1.获取
        $userModel = model(UserModel::class);
        $departmentId = $userModel->where(['id' => $userId])->getField('department_id');

        // 获取钉钉配置
        $optionsService = new OptionsService();
        $dingTalkSettings = $optionsService->getOptionsData("dingtalk_settings");

        if (!empty($dingTalkSettings)) {
            foreach ($dingTalkSettings as $dingTalkItem) {
                if (in_array($departmentId, $dingTalkItem['control_department'])) {
                    $this->config = $dingTalkItem;
                }
            }
        }
    }

    /**
     * 获取部门用户列表
     * @param $userList
     * @param $departmentId
     * @param $offset
     * @param $size
     * @return array
     */
    protected function getDepartmentUserList(&$userList, $departmentId, $offset, $size)
    {
        $userData = $this->dingTalkApp->user->getDetailedUsers($departmentId, $offset, $size);

        if (!empty($userData['userlist'])) {
            foreach ($userData['userlist'] as $userItem) {
                $userList[] = $userItem;
            }
        }

        if ($userData['hasMore']) {
            $offset = $offset + $size;
            return $this->getDepartmentUserList($userList, $departmentId, $offset, $size);
        }

        return $userList;
    }

    /**
     * 生成钉钉缓存
     * @return array
     */
    public function generateDingTalkCache()
    {
        $userMapByMobile = [];
        // 读取缓存
        $oldDingTalkUserCache = S($this->cacheKey);

        if (!empty($oldDingTalkUserCache)) {
            // 有缓存，判断缓存时间是否是今天
            $todayDate = get_format_date(time(), 0);
            $cacheDate = get_format_date($oldDingTalkUserCache['cache_time'], 0);
            if ($todayDate === $cacheDate) {
                // 今天缓存直接返回
                return $oldDingTalkUserCache['user_map'];
            }
        }

        // 缓存时间戳
        if (!empty($this->dingTalkApp)) {
            $departmentList = $this->dingTalkApp->department->list(null, true); // 获取子部门

            if ($departmentList['errcode'] === 0) {
                $userList = [];
                foreach ($departmentList['department'] as $departmentItem) {
                    // 获取每个部门下面用户
                    $offset = 0; // 偏移量
                    $size = 100; // 分页数量
                    $this->getDepartmentUserList($userList, $departmentItem['id'], $offset, $size);
                }

                /**
                 * 缓存用户列表
                 * 1、以phone为key值
                 * 2、每天缓存一次
                 */
                $userMapByMobile = array_column($userList, null, 'mobile');

                $dingTalkUserCache = [
                    'user_map' => $userMapByMobile,
                    'cache_time' => time()
                ];

                S($this->cacheKey, $dingTalkUserCache);
            }
        }

        return $userMapByMobile;
    }

    /**
     * 获取公司排班时间
     * @param $date
     * @return mixed
     */
    public function getSchedulingTime($date)
    {
        return $this->dingTalkApp->attendance->schedules($date);
    }

    /**
     * 获取指定人的考勤记录最后打卡时间
     * @param $userIds
     * @param $time
     * @return array
     */
    public function getWorkAttendanceByUserId($userIds, $time)
    {
        $userDingTalkIds = [];
        $userMapByMobile = $this->generateDingTalkCache();

        // 获取当前用户id
        $userModel = model(UserModel::class);
        $userData = $userModel->field('id,phone')->where(['id' => ['IN', join(',', unique_arr($userIds))]])->select();
        foreach ($userData as &$userItem) {
            if (array_key_exists($userItem['phone'], $userMapByMobile)) {
                $userItem['dingTalk_user_id'] = $userMapByMobile[$userItem['phone']]['userid'];
                $userDingTalkIds[] = $userMapByMobile[$userItem['phone']]['userid'];
            } else {
                $userItem['dingTalk_user_id'] = 0;
            }
        }

        if (empty($userDingTalkIds)) {
            return [];
        }

        // 当前日期往前推一天
        $beforeTime = $time - 86400;

        $params = [
            'userIds' => $userDingTalkIds,
            'checkDateFrom' => get_format_date($beforeTime, 1),
            'checkDateTo' => get_format_date($time, 1),
            'isI18n' => false
        ];

        $recordsData = $this->dingTalkApp->attendance->records($params);

        // 查找当前人员最后下班时间
        $userAttendanceMapData = [];
        foreach ($recordsData['recordresult'] as $recordsItem) {
            if (array_key_exists('checkType', $recordsItem) && $recordsItem['checkType'] === 'OffDuty') {
                $offDutyTime = $recordsItem['gmtCreate'] / 1000;
                if (array_key_exists($recordsItem['userId'], $userAttendanceMapData)) {
                    if ($offDutyTime > $userAttendanceMapData[$recordsItem['userId']]) {
                        $userAttendanceMapData[$recordsItem['userId']] = $offDutyTime;
                    }
                } else {
                    $userAttendanceMapData[$recordsItem['userId']] = $offDutyTime;
                }
            }

        }

        // 填充回用户数据字典
        $userMapData = [];
        foreach ($userData as $userItem) {
            if (array_key_exists($userItem['dingTalk_user_id'], $userAttendanceMapData)) {
                $offDutyTime = $userAttendanceMapData[$userItem['dingTalk_user_id']];
            } else {
                $offDutyTime = 0;
            }

            //  获取排班情况
            $offDutyCheckTime = 0;
            if (!empty($userItem['dingTalk_user_id'])) {
                $userDingTalkGroup = $this->dingTalkApp->attendance->userGroup($userItem['dingTalk_user_id']);

                if ($userDingTalkGroup['errcode'] === 0 && !empty($userDingTalkGroup['result'])) {
                    $offDutyCheckTime = date('H:i:s', strtotime($userDingTalkGroup['result']['classes'][0]['sections'][0]['times'][1]['check_time']));
                }
            }

            $userMapData[$userItem['id']] = [
                'off_duty_time' => $offDutyTime,
                'off_duty_check_time' => $offDutyCheckTime,
                'dingTalk_user_id' => $userItem['dingTalk_user_id']
            ];
        }

        return $userMapData;
    }


    /**
     * 获取钉钉user_id
     * @param $userId
     * @return int|mixed
     */
    public function getDingTalkUserId($userId)
    {
        $this->init($userId);
        $userMapByMobile = $this->generateDingTalkCache();
        // 获取当前用户id
        $userModel = model(UserModel::class);
        $phone = $userModel->where("id=$userId")->getField('phone');

        if (array_key_exists($phone, $userMapByMobile)) {
            $dingTalkUserId = $userMapByMobile[$phone]['userid'];
        } else {
            $dingTalkUserId = 0;
        }
        return $dingTalkUserId;
    }

    /**
     * 定时插入前一天的所有打卡记录
     */
    public function synchronousPunchRecord()
    {
        $userModel = model(UserModel::class);
        $userList = $userModel
            ->field('id,phone,department_id')
            ->where([
                'department_id' => ['gt', 0],
                'phone' => ['neq', '']
            ])
            ->select();

        // 获取钉钉配置
        $optionsService = new OptionsService();
        $dingTalkSettings = $optionsService->getOptionsData("dingtalk_settings");


        // 按相同钉钉配置来分组用户
        foreach ($userList as $userItem) {
            foreach ($dingTalkSettings as &$dingTalkSettingItem) {
                if (in_array($userItem['department_id'], $dingTalkSettingItem['control_department'])) {
                    if (array_key_exists('user_list', $dingTalkSettingItem)) {
                        $dingTalkSettingItem['user_list'][] = $userItem;
                    } else {
                        $dingTalkSettingItem['user_list'] = [$userItem];
                    }
                    break;
                }
            }
        }
        //获取昨天时间范围
        $startTime = strtotime(date('Y-m-d 00:00:00', strtotime('-1 day')));
        $endTime = strtotime(date('Y-m-d 23:59:59', strtotime('-1 day')));
//        $startTime = strtotime('2019-12-03 00:00:00');
//        $endTime = strtotime('2019-12-03 23:59:59');
        try {
            $list = [];
            foreach ($dingTalkSettings as $dingTalkSetting) {
                if (array_key_exists('user_list', $dingTalkSetting)) {
                    $this->setConfig([
                        "app_key" => $dingTalkSetting['app_key'],
                        "corp_id" => $dingTalkSetting['corp_id'],
                        "node_name" => $dingTalkSetting['node_name'],
                        "app_secret" => $dingTalkSetting['app_secret']
                    ]);

                    $this->init();
                    //获取时间范围内打卡记录
                    $dingTalkList = $this->getDingTalkUserResults($dingTalkSetting['user_list'], $startTime, $endTime);
                    if (!empty($dingTalkList)) {
                        $list = array_merge($list, $dingTalkList);
                    }
                }
            }
            if (!empty($list)) { //存在打卡记录
                //插入数据库 TODO
            }

        } catch (\Exception $e) {
            // 报错信息
            throw_strack_exception($e->getMessage(), $e->getCode());
        }

    }

    /**
     * 获取指定用户的考勤记录
     * @param $userList
     * @param $startTime
     * @param $endTime
     * @return array
     */
    public function getDingTalkUserRecords($userList, $startTime, $endTime)
    {
        $userDingTalkIds = [];
        $userMapByMobile = $this->generateDingTalkCache();

        foreach ($userList as $userItem) {
            if (array_key_exists($userItem['phone'], $userMapByMobile)) {
                $userDingTalkIds[] = $userMapByMobile[$userItem['phone']]['userid'];
            }
        }

        if (empty($userDingTalkIds)) {
            return [];
        }


        $resultList = [];

        //分页 考虑到企业内的员工id列表，最多不能超过50个
        $page = ceil(count($userDingTalkIds) / 50);
        for ($i = 1; $i <= $page; $i++) {
            $start = ($i - 1) * 50;
            $dingUserIds = array_slice($userDingTalkIds, $start, 50);
            $params = [
                'userIds' => $dingUserIds,
                'checkDateFrom' => get_format_date($startTime, 1),
                'checkDateTo' => get_format_date($endTime, 1),
                'isI18n' => false
            ];
            $recordsData = $this->dingTalkApp->attendance->records($params);
            if (!empty($recordsData['recordresult'])) {
                $resultList = array_merge($resultList, $recordsData['recordresult']);
            }
        }
        return $resultList;
    }

    /**
     * 获取指定用户的考勤结果
     * @param $userList
     * @param $startTime
     * @param $endTime
     * @return array
     */
    public function getDingTalkUserResults($userList, $startTime, $endTime)
    {
        $userDingTalkIds = [];
        $userMapByMobile = $this->generateDingTalkCache();

        foreach ($userList as $userItem) {
            if (array_key_exists($userItem['phone'], $userMapByMobile)) {
                $userDingTalkIds[] = $userMapByMobile[$userItem['phone']]['userid'];
            }
        }

        if (empty($userDingTalkIds)) {
            return [];
        }


        $resultList = [];

        //分页 考虑到企业内的员工id列表，最多不能超过50个
        $page = ceil(count($userDingTalkIds) / 50);
        for ($i = 1; $i <= $page; $i++) {
            $start = ($i - 1) * 50;
            $dingUserIds = array_slice($userDingTalkIds, $start, 50);
            $j = 1;
            do {
                $offset = ($j - 1) * 50;
                $params = [
                    'userIdList' => $dingUserIds,
                    'workDateFrom' => get_format_date($startTime, 1),
                    'workDateTo' => get_format_date($endTime, 1),
                    'offset' => $offset,
                    'limit' => 50 //最大值为50
                ];
                $recordsData = $this->dingTalkApp->attendance->results($params);
                if (!empty($recordsData['recordresult'])) {
                    $resultList = array_merge($resultList, $recordsData['recordresult']);
                }
                $j++;
            } while (isset($recordsData['hasMore']) && $recordsData['hasMore'] == true);
        }
        return $resultList;
    }

}
